﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;

namespace MTP.Serialize
{
    class MTPCoreUtil
    {

        /// <summary>
        /// 获取一个端口号
        /// </summary>
        /// <returns></returns>
        public static int PortNext()
        {
            IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipendpoints = properties.GetActiveTcpListeners();
            int port = 17000;

            while (ipendpoints.Any(a => a.Port == port))
            {
                port++;
            }
            return port;
        }

        public static bool TryParseMtpUrl(string url, out int port, out string hostName)
        {
            port = 17000;
            hostName = "localhost";
            if (url == null)
            {
                return false;
            }
            if (url.ToLower().StartsWith("mtp://"))
            {
                url = url.Substring(6);
            }
            var urls = url.Split('/');
            var strs = urls[0].Split(':');
            hostName = strs[0];
            if (string.IsNullOrEmpty(hostName))
            {
                return false;
            }
            if (strs.Length > 1 && !int.TryParse(strs[1], out port))
            {
                port = PortNext();
            }
            return true;
        }

        public static IEnumerable<TypeInfo> FindTypeByAttribute<T>() where T : Attribute
        {
            var attrType = typeof(T);
            Assembly assembly = Assembly.GetEntryAssembly();

            foreach (var typeInfo in assembly.DefinedTypes)
            {
                if (typeInfo.GetCustomAttribute(attrType) != null)
                {
                    yield return typeInfo;
                }
            }
        }

        private static object GetTaskResult(object result)
        {
            if (result is Task task)
            {
                task.GetAwaiter().GetResult();
                var taskType = result.GetType();
                if (taskType.GetGenericArguments().Length > 0)
                {
                    return taskType.GetProperty("Result").GetValue(result, null);
                }
                else
                {
                    return null;
                }
            }
            return result;
        }
        public static object[] MethodsInvoke(object instance, MethodInfo[] methodInfos, string methodname, Func<ParameterInfo[], object[]> argBind)
        {
            var method = methodInfos.Where(a => a.Name.Equals(methodname, StringComparison.OrdinalIgnoreCase))
                .Select(methodInfo => new
                {
                    methodInfo,
                    args = argBind(methodInfo.GetParameters())
                })
                .Where(a => a.args != null).FirstOrDefault();

            if (method == null)
            {
                throw new NotImplementedException(methodname);
            }
            object result = GetTaskResult(method.methodInfo.Invoke(instance, method.args));
            var ps = method.methodInfo.GetParameters();
            var apps = new List<object>() { result };
            for (int i = 0; i < ps.Length; i++)
            {
                if (ps[i].IsOut || ps[i].ParameterType.IsByRef)
                {
                    apps.Add(method.args[i]);
                }
            }
            return apps.ToArray();
        }

        public static Dictionary<string, string> GetHeaderDict(string header)
        {
            return header.Split("&").Select(a => a.Split('=')).ToDictionary(a => a[0], a => a.Length > 1 ? a[1] : "");
        }

        public static string GetHeaderString(Dictionary<string, string> dict)
        {
            return string.Join("&", dict.Select(a => $"{a.Key}={HttpUtility.UrlEncode(a.Value)}"));
        }
    }
}
